Model Deployment : Exploring Modular Application Programming Interface Frameworks For Serving Model Predictions¶
- 1. Table of Contents
- 2. Summary
- 3. References
1. Table of Contents ¶
1.1. Project Background ¶
1.1.1 Categorical Classification ¶
1.1.1.1 Data Background ¶
1.1.1.2 Model Background ¶
1.1.1.3 Deployment Background ¶
1.1.2 Survival Prediction ¶
1.1.2.1 Data Background ¶
1.1.2.2 Model Background ¶
1.1.2.3 Deployment Background ¶
1.1.3 Image Classification ¶
1.1.3.1 Data Background ¶
1.1.3.2 Model Background ¶
1.1.3.3 Deployment Background ¶
1.2. Application Programming Interface (API) Development Using the FastAPI Framework ¶
1.2.1 Categorical Classification ¶
1.2.1.1 API Building ¶
1.2.1.2 API Testing ¶
In [1]:
##################################
# Loading Python Libraries
##################################
import requests
In [2]:
##################################
# Defining the base URL of the API
# for the categorical classification model
##################################
CC_FASTAPI_BASE_URL = "http://127.0.0.1:8000"
In [3]:
##################################
# Defining the input values for an individual test case
##################################
individual_test_case = {
"features_individual": [1, 0, 0, 0, 0, 1, 0, 0, 1, 1]
}
In [4]:
##################################
# Defining the input values for a batch of cases
##################################
batch_test_case = {
"features_list": [
[1, 0, 0, 0, 0, 1, 0, 0, 1, 1],
[1, 0, 1, 0, 1, 1, 0, 1, 1, 1]
]
}
In [5]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{CC_FASTAPI_BASE_URL}/")
if response.status_code == 200:
print("Root Endpoint Response:", response.json())
else:
print("Error:", response.status_code, response.text)
Root Endpoint Response: {'message': 'Welcome to the Categorical Classification API!'}
In [6]:
##################################
# Generating a POST endpoint request for
# computing the risk index,
# estimating the lung cancer probability,
# and predicting the risk category
# of an individual test case
##################################
response = requests.post(f"{CC_FASTAPI_BASE_URL}/predict-individual-logit-probability-class", json=individual_test_case)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'logit': -1.2117837409390746,
'probability': 0.22938559072691203,
'risk_class': 'Low-Risk'}
In [7]:
##################################
# Sending a POST endpoint request for
# computing the risk index,
# estimating the lung cancer probability,
# and predicting the risk category
# of a list of train cases
##################################
response = requests.post(f"{CC_FASTAPI_BASE_URL}/predict-list-logit-probability-class", json=batch_test_case)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'logit': [-1.2117837409390746, 3.4784950973590973],
'probability': [0.22938559072691203, 0.9700696569701589],
'logit_sorted': [-1.2117837409390746, 3.4784950973590973],
'probability_sorted': [0.22938559072691203, 0.9700696569701589]}
In [8]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_test_case = {"features": [1, 0, 1]}
response = requests.post(f"{CC_FASTAPI_BASE_URL}/predict-individual-logit-probability-class", json=malformed_test_case)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
Error: 422 {"detail":[{"type":"missing","loc":["body","features_individual"],"msg":"Field required","input":{"features":[1,0,1]}}]}
1.2.2 Survival Prediction ¶
1.2.2.1 API Building ¶
1.2.2.2 API Testing ¶
In [9]:
##################################
# Loading Python Libraries
##################################
import requests
import json
import pandas as pd
import base64
from IPython.display import display
from PIL import Image
In [10]:
##################################
# Defining the base URL of the API
# for the survival prediction model
##################################
SP_FASTAPI_BASE_URL = "http://127.0.0.1:8001"
In [11]:
##################################
# Defining the input values for an individual test case
##################################
single_test_case = {
"features_individual": [43, 0, 75, 1, 0.75, 100]
}
In [12]:
##################################
# Defining the input values for a batch of cases
##################################
train_list = {
"features_list": [
[43, 0, 75, 1, 0.75, 100],
[70, 1, 20, 1, 0.75, 100]
]
}
In [13]:
##################################
# Defining the input values for a batch of cases for binning request
##################################
bin_request = {
"X_original_list": [
{"AGE": -0.10, "EJECTION_FRACTION": -0.10, "SERUM_CREATININE ": -0.10, "SERUM_SODIUM": -0.10},
{"AGE": 0.20, "EJECTION_FRACTION": 0.20, "SERUM_CREATININE ": 0.20, "SERUM_SODIUM": 0.20},
{"AGE": 0.90, "EJECTION_FRACTION": 0.90, "SERUM_CREATININE ": 0.90, "SERUM_SODIUM": 0.90}
],
"numeric_feature": "AGE"
}
In [14]:
##################################
# Defining the input values for a batch of cases for Kaplan-Meier plotting
##################################
km_request = {
"df": [
{"TIME": 0, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 25, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 50, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 100, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 125, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 150, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 175, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 200, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 225, "DEATH_EVENT": 1, "AGE": "Low"},
{"TIME": 250, "DEATH_EVENT": 1, "AGE": "Low"},
{"TIME": 0, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 25, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 50, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 100, "DEATH_EVENT": 1, "AGE": "High"},
{"TIME": 125, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 150, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 175, "DEATH_EVENT": 1, "AGE": "High"},
{"TIME": 200, "DEATH_EVENT": 1, "AGE": "High"},
{"TIME": 225, "DEATH_EVENT": 1, "AGE": "High"},
{"TIME": 250, "DEATH_EVENT": 1, "AGE": "High"},
],
"cat_var": "AGE",
"new_case_value": "Low"
}
In [15]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{SP_FASTAPI_BASE_URL}/")
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'message': 'Welcome to the Survival Prediction API!'}
In [16]:
##################################
# Sending a POST endpoint request for
# generating the heart failure survival profile,
# estimating the heart failure survival probabilities,
# and predicting the risk category
# of an individual test case
##################################
response = requests.post(f"{SP_FASTAPI_BASE_URL}/compute-individual-coxph-survival-probability-class/", json=single_test_case)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'survival_function': [0.9973812917524568,
0.9920416812438736,
0.9893236791425079,
0.972381113071464,
0.9693179903073035,
0.9631930672135339,
0.9631930672135339,
0.9600469571766689,
0.9600469571766689,
0.9568596864927983,
0.9536305709158891,
0.9471625843882805,
0.93729581350105,
0.9338986486591409,
0.93048646553474,
0.9270645831787163,
0.9202445006124622,
0.9167715111530355,
0.9132845175345189,
0.9097550958520674,
0.9097550958520674,
0.9097550958520674,
0.9060810720432387,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.8985598696587259,
0.8985598696587259,
0.8985598696587259,
0.8945287485160898,
0.8945287485160898,
0.8945287485160898,
0.8945287485160898,
0.8901959645503091,
0.8812352215018253,
0.8812352215018253,
0.8812352215018253,
0.8812352215018253,
0.8764677174183527,
0.8764677174183527,
0.8764677174183527,
0.8764677174183527,
0.8709113650481243,
0.8709113650481243,
0.8652494086650531,
0.8593884303802698,
0.8593884303802698,
0.8593884303802698,
0.8593884303802698,
0.8593884303802698,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8459534502216807,
0.8389821875092403,
0.8319419786276306,
0.8246669811915435,
0.8099879066057215,
0.8099879066057215,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7848178617845467,
0.7848178617845467,
0.7848178617845467,
0.7848178617845467,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7337716342207724,
0.7337716342207724,
0.7337716342207724,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696],
'survival_time': [50, 100, 150, 200, 250],
'survival_probabilities': [90.97550958520674,
87.64677174183527,
84.59534502216806,
78.48178617845467,
70.70184115456696],
'risk_category': 'Low-Risk'}
In [17]:
##################################
# Sending a POST endpoint request for
# generating the heart failure survival profile and
# estimating the heart failure survival probabilities
# of a list of train cases
##################################
response = requests.post(f"{SP_FASTAPI_BASE_URL}/compute-list-coxph-survival-profile/", json=train_list)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'survival_profiles': [[0.9973812917524568,
0.9920416812438736,
0.9893236791425079,
0.972381113071464,
0.9693179903073035,
0.9631930672135339,
0.9631930672135339,
0.9600469571766689,
0.9600469571766689,
0.9568596864927983,
0.9536305709158891,
0.9471625843882805,
0.93729581350105,
0.9338986486591409,
0.93048646553474,
0.9270645831787163,
0.9202445006124622,
0.9167715111530355,
0.9132845175345189,
0.9097550958520674,
0.9097550958520674,
0.9097550958520674,
0.9060810720432387,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.8985598696587259,
0.8985598696587259,
0.8985598696587259,
0.8945287485160898,
0.8945287485160898,
0.8945287485160898,
0.8945287485160898,
0.8901959645503091,
0.8812352215018253,
0.8812352215018253,
0.8812352215018253,
0.8812352215018253,
0.8764677174183526,
0.8764677174183526,
0.8764677174183526,
0.8764677174183526,
0.8709113650481243,
0.8709113650481243,
0.8652494086650531,
0.8593884303802697,
0.8593884303802697,
0.8593884303802697,
0.8593884303802697,
0.8593884303802697,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8459534502216807,
0.8389821875092403,
0.8319419786276306,
0.8246669811915435,
0.8099879066057215,
0.8099879066057215,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7848178617845467,
0.7848178617845467,
0.7848178617845467,
0.7848178617845467,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7337716342207724,
0.7337716342207724,
0.7337716342207724,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695],
[0.9761144218801228,
0.928980888267716,
0.905777064852962,
0.7724242339590301,
0.7502787164583535,
0.7076872741961866,
0.7076872741961866,
0.6866593185026403,
0.6866593185026403,
0.6659260634219393,
0.6454915885099762,
0.6062342264686207,
0.5504405490863784,
0.5323184765768243,
0.5146536440658629,
0.49746533888245986,
0.464726413395405,
0.4488047347163327,
0.433309930422515,
0.4181140392975694,
0.4181140392975694,
0.4181140392975694,
0.4028020116306455,
0.38802639234746467,
0.38802639234746467,
0.38802639234746467,
0.38802639234746467,
0.38802639234746467,
0.373006008573048,
0.373006008573048,
0.373006008573048,
0.35785929480690143,
0.35785929480690143,
0.35785929480690143,
0.35785929480690143,
0.3421927616040032,
0.3117176431598899,
0.3117176431598899,
0.3117176431598899,
0.3117176431598899,
0.29651072362871467,
0.29651072362871467,
0.29651072362871467,
0.29651072362871467,
0.2796248763802668,
0.2796248763802668,
0.2633052706162029,
0.24731169874453887,
0.24731169874453887,
0.24731169874453887,
0.24731169874453887,
0.24731169874453887,
0.23051507888001282,
0.23051507888001282,
0.23051507888001282,
0.23051507888001282,
0.23051507888001282,
0.213871875082776,
0.19816204676152543,
0.18334919195124752,
0.16908728217620728,
0.1432835564355214,
0.1432835564355214,
0.119778195679268,
0.119778195679268,
0.119778195679268,
0.119778195679268,
0.119778195679268,
0.10710184631976834,
0.10710184631976834,
0.10710184631976834,
0.10710184631976834,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.07544024472233593,
0.07544024472233593,
0.07544024472233593,
0.07544024472233593,
0.07544024472233593,
0.05761125190131533,
0.05761125190131533,
0.05761125190131533,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404]]}
In [18]:
##################################
# Sending a POST endpoint request for
# creating dichotomous bins for the numeric features
# of a list of train cases
##################################
response = requests.post(f"{SP_FASTAPI_BASE_URL}/bin-numeric-model-feature/", json=bin_request)
if response.status_code == 200:
display("Response:", pd.DataFrame(response.json()))
else:
print("Error:", response.status_code, response.text)
'Response:'
| AGE | EJECTION_FRACTION | SERUM_CREATININE | SERUM_SODIUM | |
|---|---|---|---|---|
| 0 | Low | -0.1 | -0.1 | -0.1 |
| 1 | High | 0.2 | 0.2 | 0.2 |
| 2 | High | 0.9 | 0.9 | 0.9 |
In [19]:
##################################
# Sending a POST endpoint request for
# plotting the estimated survival profiles
# using Kaplan-Meier Plots
##################################
response = requests.post(f"{SP_FASTAPI_BASE_URL}/plot-kaplan-meier/", json=km_request)
if response.status_code == 200:
plot_data = response.json()["plot"]
# Decoding and displaying the plot
img = base64.b64decode(plot_data)
with open("kaplan_meier_plot.png", "wb") as f:
f.write(img)
display(Image.open("kaplan_meier_plot.png"))
else:
print("Error:", response.status_code, response.text)
In [20]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_test_case = {"features": [43, 0, 75, 1, 0.75]}
response = requests.post(f"{SP_FASTAPI_BASE_URL}/compute-individual-coxph-survival-probability-class", json=malformed_test_case)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
Error: 422 {"detail":[{"type":"missing","loc":["body","features_individual"],"msg":"Field required","input":{"features":[43,0,75,1,0.75]}}]}
1.2.3 Image Classification ¶
1.2.3.1 API Building ¶
1.2.3.2 API Testing ¶
In [21]:
##################################
# Loading Python Libraries
##################################
import requests
import json
import base64
from IPython.display import display
from PIL import Image
import matplotlib.pyplot as plt
import io
from tensorflow.keras.utils import load_img
import os
import mimetypes
In [22]:
##################################
# Defining the base URL of the API
# for the image classification model
##################################
IC_FASTAPI_BASE_URL = "http://127.0.0.1:8002"
In [23]:
##################################
# Defining the file path for an individual test image
##################################
IMAGES_PATH = r"image_classification_study\images"
image_path = (os.path.join("..",IMAGES_PATH, "test_image.jpg"))
In [24]:
##################################
# Automatically determining the filename and content type
##################################
image_path_filename = os.path.basename(image_path)
image_path_content_type, _ = mimetypes.guess_type(image_path)
In [25]:
##################################
# Visualizing the individual test image
##################################
try:
image = Image.open(image_path)
print(f"Image File Path: {image_path}")
print(f"Image Format: {image.format}")
print(f"Image Size: {image.size}")
print(f"Image Mode: {image.mode}")
except Exception as e:
print(f"Error loading image: {e}")
plt.imshow(image)
plt.axis('off')
plt.title("Test Image")
plt.show()
Image File Path: ..\image_classification_study\images\test_image.jpg Image Format: JPEG Image Size: (215, 234) Image Mode: RGB
In [26]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{IC_FASTAPI_BASE_URL}/")
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'message': 'Welcome to the Image Classification API!'}
In [27]:
##################################
# Sending a POST endpoint request for
# ensuring that the file upload mechanism is working
# by returning the the file metadata
##################################
with open(image_path, "rb") as file:
files = {"file": (image_path_filename, file, image_path_content_type)}
response = requests.post(f"{IC_FASTAPI_BASE_URL}/test-file-upload/", files=files)
if response.status_code == 200:
result = response.json()
print("File Upload Test Result:")
print(f"Filename: {result['filename']}")
print(f"Content Type: {result['content_type']}")
print(f"Size: {result['size']} bytes")
else:
print(f"Error: {response.status_code} - {response.text}")
File Upload Test Result: Filename: test_image.jpg Content Type: image/jpeg Size: 12103 bytes
In [28]:
##################################
# Sending a POST endpoint request for
# predicting the image category and
# estimating class probabilities
# of an individual test image
##################################
with open(image_path, "rb") as file:
files = {"file": ("image.jpg", file, "image/jpeg")}
response = requests.post(f"{IC_FASTAPI_BASE_URL}/predict-image-category-class-probability/", files=files)
if response.status_code == 200:
result = response.json()
print("Prediction Result:")
print(f"Predicted Class: {result['predicted_class']}")
print("Probabilities:")
for cls, prob in result["probabilities"].items():
print(f"{cls}: {prob:.5f}%")
else:
print(f"Error: {response.status_code} - {response.text}")
Prediction Result: Predicted Class: Meningioma Probabilities: No Tumor: 12.94989% Glioma: 0.02788% Meningioma: 87.02222% Pituitary: 0.00002%
In [29]:
##################################
# Sending a POST endpoint request for
# formulating the gradient class activation map
# from the output of the first to third convolutional layers and
# and superimposing on the actual image
##################################
with open(image_path, "rb") as file:
files = {"file": ("image.jpg", file, "image/jpeg")}
response = requests.post(f"{IC_FASTAPI_BASE_URL}/visualize-image-gradcam/", files=files)
if response.status_code == 200:
plot_data = response.json()["plot"]
# Decoding and displaying the plot
img = base64.b64decode(plot_data)
with open("image_gradcam_plot.png", "wb") as f:
f.write(img)
display(Image.open("image_gradcam_plot.png"))
else:
print(f"Error: {response.status_code} - {response.text}")
In [30]:
##################################
# Defining the file path for an individual test image
##################################
IMAGES_PATH = r"image_classification_study\images"
malformed_image_path = (os.path.join("..",IMAGES_PATH, "test_image.png"))
In [31]:
##################################
# Automatically determining the filename and content type
##################################
malformed_image_path_filename = os.path.basename(image_path)
malformed_image_path_content_type, _ = mimetypes.guess_type(malformed_image_path)
In [32]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
with open(malformed_image_path, "rb") as file:
files = {"file": (malformed_image_path_filename, file, malformed_image_path_content_type)}
response = requests.post(f"{IC_FASTAPI_BASE_URL}/test-file-upload/", files=files)
if response.status_code == 200:
result = response.json()
print("File Upload Test Result:")
print(f"Filename: {result['filename']}")
print(f"Content Type: {result['content_type']}")
print(f"Size: {result['size']} bytes")
else:
print(f"Error: {response.status_code} - {response.text}")
Error: 400 - {"detail":"File must be a JPEG image"}
1.3. Application Programming Interface (API) Development Using the Flask Framework ¶
1.3.1 Categorical Classification ¶
1.3.1.1 API Building ¶
1.3.1.2 API Testing ¶
In [33]:
##################################
# Loading Python Libraries
##################################
import requests
In [34]:
##################################
# Defining the base URL of the API
# for the categorical classification model
##################################
CC_FLASKAPI_BASE_URL = "http://127.0.0.1:5000/"
In [35]:
##################################
# Defining the input values for an individual test case
##################################
individual_test_case = {
"features_individual": [1, 0, 0, 0, 0, 1, 0, 0, 1, 1]
}
In [36]:
##################################
# Defining the input values for a batch of cases
##################################
batch_test_case = {
"features_list": [
[1, 0, 0, 0, 0, 1, 0, 0, 1, 1],
[1, 0, 1, 0, 1, 1, 0, 1, 1, 1]
]
}
In [37]:
##################################
# Generating a GET endpoint request for
# validating API service connection
##################################
response = requests.get(f"{CC_FLASKAPI_BASE_URL}/")
if response.status_code == 200:
print("Root Endpoint Response:", response.json())
else:
print("Error:", response.status_code, response.text)
Root Endpoint Response: {'message': 'Welcome to the Categorical Classification API!'}
In [38]:
##################################
# Generating a POST endpoint request for
# computing the risk index,
# estimating the lung cancer probability,
# and predicting the risk category
# of an individual test case
##################################
response = requests.post(f"{CC_FLASKAPI_BASE_URL}/predict-individual-logit-probability-class", json=individual_test_case)
if response.status_code == 200:
print("Individual Test Case Response:", response.json())
else:
print("Error:", response.status_code, response.text)
Individual Test Case Response: {'logit': -1.2117837409390746, 'probability': 0.22938559072691203, 'risk_class': 'Low-Risk'}
In [39]:
##################################
# Sending a POST endpoint request for
# computing the risk index,
# estimating the lung cancer probability,
# and predicting the risk category
# of a list of train cases
##################################
response = requests.post(f"{CC_FLASKAPI_BASE_URL}/predict-list-logit-probability-class", json=batch_test_case)
if response.status_code == 200:
print("Batch Test Case Response:", response.json())
else:
print("Error:", response.status_code, response.text)
Batch Test Case Response: {'logit': [-1.2117837409390746, 3.4784950973590973], 'logit_sorted': [-1.2117837409390746, 3.4784950973590973], 'probability': [0.22938559072691203, 0.9700696569701589], 'probability_sorted': [0.22938559072691203, 0.9700696569701589]}
In [40]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_test_case = {"features": [1, 0, 1]}
response = requests.post(f"{CC_FLASKAPI_BASE_URL}/predict-individual-logit-probability-class", json=malformed_test_case)
if response.status_code == 200:
print("Malformed Test Case Response:", response.json())
else:
print("Error:", response.status_code, response.text)
Error: 400 {"error":"'features_individual'"}
1.3.2 Survival Prediction ¶
1.3.2.1 API Building ¶
1.3.2.2 API Testing ¶
In [41]:
##################################
# Loading Python Libraries
##################################
import requests
import json
import pandas as pd
import base64
from IPython.display import Image, display
In [42]:
##################################
# Defining the base URL of the API
# for the survival prediction model
##################################
SP_FLASKAPI_BASE_URL = "http://127.0.0.1:5001"
In [43]:
##################################
# Defining the input values for an individual test case
##################################
single_test_case = {
"features_individual": [43, 0, 75, 1, 0.75, 100]
}
In [44]:
##################################
# Defining the input values for a batch of cases
##################################
train_list = {
"features_list": [
[43, 0, 75, 1, 0.75, 100],
[70, 1, 20, 1, 0.75, 100]
]
}
In [45]:
##################################
# Defining the input values for a batch of cases for binning request
##################################
bin_request = {
"X_original_list": [
{"AGE": -0.10, "EJECTION_FRACTION": -0.10, "SERUM_CREATININE": -0.10, "SERUM_SODIUM": -0.10},
{"AGE": 0.20, "EJECTION_FRACTION": 0.20, "SERUM_CREATININE": 0.20, "SERUM_SODIUM": 0.20},
{"AGE": 0.90, "EJECTION_FRACTION": 0.90, "SERUM_CREATININE": 0.90, "SERUM_SODIUM": 0.90}
],
"numeric_feature": "AGE"
}
In [46]:
##################################
# Defining the input values for a batch of cases for Kaplan-Meier plotting
##################################
km_request = {
"df": [
{"TIME": 0, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 25, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 50, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 100, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 125, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 150, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 175, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 200, "DEATH_EVENT": 0, "AGE": "Low"},
{"TIME": 225, "DEATH_EVENT": 1, "AGE": "Low"},
{"TIME": 250, "DEATH_EVENT": 1, "AGE": "Low"},
{"TIME": 0, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 25, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 50, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 100, "DEATH_EVENT": 1, "AGE": "High"},
{"TIME": 125, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 150, "DEATH_EVENT": 0, "AGE": "High"},
{"TIME": 175, "DEATH_EVENT": 1, "AGE": "High"},
{"TIME": 200, "DEATH_EVENT": 1, "AGE": "High"},
{"TIME": 225, "DEATH_EVENT": 1, "AGE": "High"},
{"TIME": 250, "DEATH_EVENT": 1, "AGE": "High"},
],
"cat_var": "AGE",
"new_case_value": "Low"
}
In [47]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{SP_FLASKAPI_BASE_URL}/")
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'message': 'Welcome to the Survival Prediction API!'}
In [48]:
##################################
# Sending a POST endpoint request for
# generating the heart failure survival profile,
# estimating the heart failure survival probabilities,
# and predicting the risk category
# of an individual test case
##################################
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/compute-individual-coxph-survival-probability-class/", json=single_test_case)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'risk_category': 'Low-Risk',
'survival_function': [0.9973812917524568,
0.9920416812438736,
0.9893236791425079,
0.972381113071464,
0.9693179903073035,
0.9631930672135339,
0.9631930672135339,
0.9600469571766689,
0.9600469571766689,
0.9568596864927983,
0.9536305709158891,
0.9471625843882805,
0.93729581350105,
0.9338986486591409,
0.93048646553474,
0.9270645831787163,
0.9202445006124622,
0.9167715111530355,
0.9132845175345189,
0.9097550958520674,
0.9097550958520674,
0.9097550958520674,
0.9060810720432387,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.8985598696587259,
0.8985598696587259,
0.8985598696587259,
0.8945287485160898,
0.8945287485160898,
0.8945287485160898,
0.8945287485160898,
0.8901959645503091,
0.8812352215018253,
0.8812352215018253,
0.8812352215018253,
0.8812352215018253,
0.8764677174183527,
0.8764677174183527,
0.8764677174183527,
0.8764677174183527,
0.8709113650481243,
0.8709113650481243,
0.8652494086650531,
0.8593884303802698,
0.8593884303802698,
0.8593884303802698,
0.8593884303802698,
0.8593884303802698,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8459534502216807,
0.8389821875092403,
0.8319419786276306,
0.8246669811915435,
0.8099879066057215,
0.8099879066057215,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7848178617845467,
0.7848178617845467,
0.7848178617845467,
0.7848178617845467,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7337716342207724,
0.7337716342207724,
0.7337716342207724,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696,
0.7070184115456696],
'survival_probabilities': [90.97550958520674,
87.64677174183527,
84.59534502216806,
78.48178617845467,
70.70184115456696],
'survival_time': [50, 100, 150, 200, 250]}
In [49]:
##################################
# Sending a POST endpoint request for
# generating the heart failure survival profile and
# estimating the heart failure survival probabilities
# of a list of train cases
##################################
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/compute-list-coxph-survival-profile/", json=train_list)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'survival_profiles': [[0.9973812917524568,
0.9920416812438736,
0.9893236791425079,
0.972381113071464,
0.9693179903073035,
0.9631930672135339,
0.9631930672135339,
0.9600469571766689,
0.9600469571766689,
0.9568596864927983,
0.9536305709158891,
0.9471625843882805,
0.93729581350105,
0.9338986486591409,
0.93048646553474,
0.9270645831787163,
0.9202445006124622,
0.9167715111530355,
0.9132845175345189,
0.9097550958520674,
0.9097550958520674,
0.9097550958520674,
0.9060810720432387,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.9024157452999795,
0.8985598696587259,
0.8985598696587259,
0.8985598696587259,
0.8945287485160898,
0.8945287485160898,
0.8945287485160898,
0.8945287485160898,
0.8901959645503091,
0.8812352215018253,
0.8812352215018253,
0.8812352215018253,
0.8812352215018253,
0.8764677174183526,
0.8764677174183526,
0.8764677174183526,
0.8764677174183526,
0.8709113650481243,
0.8709113650481243,
0.8652494086650531,
0.8593884303802697,
0.8593884303802697,
0.8593884303802697,
0.8593884303802697,
0.8593884303802697,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8528574859874233,
0.8459534502216807,
0.8389821875092403,
0.8319419786276306,
0.8246669811915435,
0.8099879066057215,
0.8099879066057215,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7943979200335176,
0.7848178617845467,
0.7848178617845467,
0.7848178617845467,
0.7848178617845467,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7741993572193384,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7555469848652164,
0.7337716342207724,
0.7337716342207724,
0.7337716342207724,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695,
0.7070184115456695],
[0.9761144218801228,
0.928980888267716,
0.905777064852962,
0.7724242339590301,
0.7502787164583535,
0.7076872741961866,
0.7076872741961866,
0.6866593185026403,
0.6866593185026403,
0.6659260634219393,
0.6454915885099762,
0.6062342264686207,
0.5504405490863784,
0.5323184765768243,
0.5146536440658629,
0.49746533888245986,
0.464726413395405,
0.4488047347163327,
0.433309930422515,
0.4181140392975694,
0.4181140392975694,
0.4181140392975694,
0.4028020116306455,
0.38802639234746467,
0.38802639234746467,
0.38802639234746467,
0.38802639234746467,
0.38802639234746467,
0.373006008573048,
0.373006008573048,
0.373006008573048,
0.35785929480690143,
0.35785929480690143,
0.35785929480690143,
0.35785929480690143,
0.3421927616040032,
0.3117176431598899,
0.3117176431598899,
0.3117176431598899,
0.3117176431598899,
0.29651072362871467,
0.29651072362871467,
0.29651072362871467,
0.29651072362871467,
0.2796248763802668,
0.2796248763802668,
0.2633052706162029,
0.24731169874453887,
0.24731169874453887,
0.24731169874453887,
0.24731169874453887,
0.24731169874453887,
0.23051507888001282,
0.23051507888001282,
0.23051507888001282,
0.23051507888001282,
0.23051507888001282,
0.213871875082776,
0.19816204676152543,
0.18334919195124752,
0.16908728217620728,
0.1432835564355214,
0.1432835564355214,
0.119778195679268,
0.119778195679268,
0.119778195679268,
0.119778195679268,
0.119778195679268,
0.10710184631976834,
0.10710184631976834,
0.10710184631976834,
0.10710184631976834,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.09446095671842468,
0.07544024472233593,
0.07544024472233593,
0.07544024472233593,
0.07544024472233593,
0.07544024472233593,
0.05761125190131533,
0.05761125190131533,
0.05761125190131533,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404,
0.040906392932898404]]}
In [50]:
##################################
# Sending a POST endpoint request for
# creating dichotomous bins for the numeric features
# of a list of train cases
##################################
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/bin-numeric-model-feature/", json=bin_request)
if response.status_code == 200:
display("Response:", pd.DataFrame(response.json()))
else:
print("Error:", response.status_code, response.text)
'Response:'
| AGE | EJECTION_FRACTION | SERUM_CREATININE | SERUM_SODIUM | |
|---|---|---|---|---|
| 0 | Low | -0.1 | -0.1 | -0.1 |
| 1 | High | 0.2 | 0.2 | 0.2 |
| 2 | High | 0.9 | 0.9 | 0.9 |
In [51]:
##################################
# Sending a POST endpoint request for
# plotting the estimated survival profiles
# using Kaplan-Meier Plots
##################################
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/plot-kaplan-meier/", json=km_request)
if response.status_code == 200:
plot_data = response.json()["plot"]
# Decoding and displaying the plot
img = base64.b64decode(plot_data)
with open("kaplan_meier_plot.png", "wb") as f:
f.write(img)
display(Image("kaplan_meier_plot.png"))
else:
print("Error:", response.status_code, response.text)
In [52]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_test_case = {"features": [43, 0, 75, 1, 0.75]}
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/compute-individual-coxph-survival-probability-class/", json=malformed_test_case)
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
Error: 400 {"error":"Missing 'features_individual' in request"}
1.3.3 Image Classification ¶
1.3.3.1 API Building ¶
1.3.3.2 API Testing ¶
In [53]:
##################################
# Loading Python Libraries
##################################
import requests
import json
import base64
from IPython.display import display
from PIL import Image
import matplotlib.pyplot as plt
import io
from tensorflow.keras.utils import load_img
import os
import mimetypes
In [54]:
##################################
# Defining the base URL of the API
# for the image classification model
##################################
IC_FLASKAPI_BASE_URL = "http://127.0.0.1:5002"
In [55]:
##################################
# Defining the file path for an individual test image
##################################
IMAGES_PATH = r"image_classification_study\images"
image_path = (os.path.join("..",IMAGES_PATH, "test_image.jpg"))
In [56]:
##################################
# Automatically determining the filename and content type
##################################
image_path_filename = os.path.basename(image_path)
image_path_content_type, _ = mimetypes.guess_type(image_path)
In [57]:
##################################
# Visualizing the individual test image
##################################
try:
image = Image.open(image_path)
print(f"Image File Path: {image_path}")
print(f"Image Format: {image.format}")
print(f"Image Size: {image.size}")
print(f"Image Mode: {image.mode}")
except Exception as e:
print(f"Error loading image: {e}")
plt.imshow(image)
plt.axis('off')
plt.title("Test Image")
plt.show()
Image File Path: ..\image_classification_study\images\test_image.jpg Image Format: JPEG Image Size: (215, 234) Image Mode: RGB
In [58]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{IC_FLASKAPI_BASE_URL}/")
if response.status_code == 200:
display("Response:", response.json())
else:
print("Error:", response.status_code, response.text)
'Response:'
{'message': 'Welcome to the Image Classification API!'}
In [59]:
##################################
# Sending a POST endpoint request for
# ensuring that the file upload mechanism is working
# by returning the the file metadata
##################################
with open(image_path, "rb") as file:
files = {"file": (image_path_filename, file, image_path_content_type)}
response = requests.post(f"{IC_FLASKAPI_BASE_URL}/test-file-upload/", files=files)
if response.status_code == 200:
result = response.json()
print("File Upload Test Result:")
print(f"Filename: {result['filename']}")
print(f"Content Type: {result['content_type']}")
print(f"Size: {result['size']} bytes")
else:
print(f"Error: {response.status_code} - {response.text}")
File Upload Test Result: Filename: test_image.jpg Content Type: image/jpeg Size: 12103 bytes
In [60]:
##################################
# Sending a POST endpoint request for
# predicting the image category and
# estimating class probabilities
# of an individual test image
##################################
with open(image_path, "rb") as file:
files = {"file": ("image.jpg", file, "image/jpeg")}
response = requests.post(f"{IC_FLASKAPI_BASE_URL}/predict-image-category-class-probability/", files=files)
if response.status_code == 200:
result = response.json()
print("Prediction Result:")
print(f"Predicted Class: {result['predicted_class']}")
print("Probabilities:")
for cls, prob in result["probabilities"].items():
print(f"{cls}: {prob:.5f}%")
else:
print(f"Error: {response.status_code} - {response.text}")
Prediction Result: Predicted Class: Meningioma Probabilities: Glioma: 0.02788% Meningioma: 87.02222% No Tumor: 12.94989% Pituitary: 0.00002%
In [61]:
##################################
# Sending a POST endpoint request for
# formulating the gradient class activation map
# from the output of the first to third convolutional layers and
# and superimposing on the actual image
##################################
with open(image_path, "rb") as file:
files = {"file": ("image.jpg", file, "image/jpeg")}
response = requests.post(f"{IC_FLASKAPI_BASE_URL}/visualize-image-gradcam/", files=files)
if response.status_code == 200:
plot_data = response.json()["plot"]
# Decoding and displaying the plot
img = base64.b64decode(plot_data)
with open("image_gradcam_plot.png", "wb") as f:
f.write(img)
display(Image.open("image_gradcam_plot.png"))
else:
print(f"Error: {response.status_code} - {response.text}")
In [62]:
##################################
# Defining the file path for an individual test image
##################################
IMAGES_PATH = r"image_classification_study\images"
malformed_image_path = (os.path.join("..",IMAGES_PATH, "test_image.png"))
In [63]:
##################################
# Automatically determining the filename and content type
##################################
malformed_image_path_filename = os.path.basename(image_path)
malformed_image_path_content_type, _ = mimetypes.guess_type(malformed_image_path)
In [64]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_image_path = (os.path.join("..",IMAGES_PATH, "test_image.png"))
with open(malformed_image_path, "rb") as file:
files = {"file": (malformed_image_path_filename, file, malformed_image_path_content_type)}
response = requests.post(f"{IC_FLASKAPI_BASE_URL}/test-file-upload/", files=files)
if response.status_code == 200:
result = response.json()
print("File Upload Test Result:")
print(f"Filename: {result['filename']}")
print(f"Content Type: {result['content_type']}")
print(f"Size: {result['size']} bytes")
else:
print(f"Error: {response.status_code} - {response.text}")
Error: 400 - {"error":"File must be a JPEG image"}
1.4. Consolidated Findings ¶
2. Summary ¶
3. References ¶
- [Book] Designing Machine Learning Systems: An Iterative Process for Production-Ready Applications by Chip Huyen
- [Book] Machine Learning Bookcamp: Build a Portfolio of Real-Life Projects by Alexey Grigorev and Adam Newmark
- [Book] Building Machine Learning Pipelines: Automating Model Life Cycles with TensorFlow by Hannes Hapke and Catherine Nelson
- [Book] Hands-On APIs for AI and Data Science: Python Development with FastAPI by Ryan Day
- [Book] Managing Machine Learning Projects: From Design to Deployment by Simon Thompson
- [Book] Building Data Science Applications with FastAPI: Develop, Manage, and Deploy Efficient Machine Learning Applications with Python by François Voron
- [Book] Microservice APIs: Using Python, Flask, FastAPI, OpenAPI and More by Jose Haro Peralta
- [Book] Machine Learning Engineering with Python: Manage the Lifecycle of Machine Learning odels using MLOps with Practical Examples by Andrew McMahon
- [Book] Introducing MLOps: How to Scale Machine Learning in the Enterprise by Mark Treveil, Nicolas Omont, Clément Stenac, Kenji Lefevre, Du Phan, Joachim Zentici, Adrien Lavoillotte, Makoto Miyazaki and Lynn Heidmann
- [Book] Practical Python Backend Programming: Build Flask and FastAPI Applications, Asynchronous Programming, Containerization and Deploy Apps on Cloud by Tim Peters
- [Python Library API] NumPy by NumPy Team
- [Python Library API] pandas by Pandas Team
- [Python Library API] seaborn by Seaborn Team
- [Python Library API] matplotlib.pyplot by MatPlotLib Team
- [Python Library API] matplotlib.image by MatPlotLib Team
- [Python Library API] matplotlib.offsetbox by MatPlotLib Team
- [Python Library API] itertools by Python Team
- [Python Library API] operator by Python Team
- [Python Library API] sklearn.experimental by Scikit-Learn Team
- [Python Library API] sklearn.impute by Scikit-Learn Team
- [Python Library API] sklearn.linear_model by Scikit-Learn Team
- [Python Library API] sklearn.preprocessing by Scikit-Learn Team
- [Python Library API] scipy by SciPy Team
- [Python Library API] sklearn.tree by Scikit-Learn Team
- [Python Library API] sklearn.ensemble by Scikit-Learn Team
- [Python Library API] sklearn.svm by Scikit-Learn Team
- [Python Library API] sklearn.metrics by Scikit-Learn Team
- [Python Library API] sklearn.model_selection by Scikit-Learn Team
- [Python Library API] imblearn.over_sampling by Imbalanced-Learn Team
- [Python Library API] imblearn.under_sampling by Imbalanced-Learn Team
- [Python Library API] SciKit-Survival by SciKit-Survival Team
- [Python Library API] SciKit-Learn by SciKit-Learn Team
- [Python Library API] StatsModels by StatsModels Team
- [Python Library API] SciPy by SciPy Team
- [Python Library API] Lifelines by Lifelines Team
- [Python Library API] tensorflow by TensorFlow Team
- [Python Library API] keras by Keras Team
- [Python Library API] pil by Pillow Team
- [Python Library API] glob by glob Team
- [Python Library API] cv2 by OpenCV Team
- [Python Library API] os by os Team
- [Python Library API] random by random Team
- [Python Library API] keras.models by TensorFlow Team
- [Python Library API] keras.layers by TensorFlow Team
- [Python Library API] keras.wrappers by TensorFlow Team
- [Python Library API] keras.utils by TensorFlow Team
- [Python Library API] keras.optimizers by TensorFlow Team
- [Python Library API] keras.preprocessing.image by TensorFlow Team
- [Python Library API] keras.callbacks by TensorFlow Team
- [Python Library API] keras.metrics by TensorFlow Team
- [Python Library API] sklearn.metrics by Scikit-Learn Team
- [Python Library API] Streamlit by Streamlit Team
- [Python Library API] Streamlit Community Cloud by Streamlit Team
- [Article] ML - Deploy Machine Learning Models Using FastAPI by Dorian Machado (Medium)
- [Article] Deploying Machine Learning Models Using FastAPI by Kevin Njagi (Medium)
- [Article] Deploy Machine Learning API with FastAPI for Free by Aniket Maurya (Lightning.AI)
- [Article] How to Use FastAPI for Machine Learning by Cheuk Ting Ho (JetBrains.Com)
- [Article] Deploying and Hosting a Machine Learning Model with FastAPI and Heroku by Michael Herman (TestDriven.IO)
- [Article] A Practical Guide to Deploying Machine Learning Models by Bala Priya (MachineLearningMastery.Com)
- [Article] Using FastAPI to Deploy Machine Learning Models by Carl Handlin (Medium)
- [Article] How to Deploy a Machine Learning Model by Maarten Grootendorst (MaartenGrootendorst.Com)
- [Article] Accelerating Machine Learning Deployment: Unleashing the Power of FastAPI and Docker by Pratyush Khare (Medium)
- [Article] Containerize and Deploy ML Models with FastAPI & Docker by Hemachandran Dhinakaran (Medium)
- [Article] Quick Tutorial to Deploy Your ML models using FastAPI and Docker by Shreyansh Singh (GitHub)
- [Article] How to Deploying Machine Learning Models in Production by Umair Akram (Medium)
- [Article] Deploying a Machine Learning Model with FastAPI: A Comprehensive Guide by Muhammad Naveed Arshad (Medium)
- [Article] Deploy Machine Learning Model with REST API using FastAPI by Yusuf Berki Yazıcıoğlu (Medium)
- [Article] Deploying An ML Model With FastAPI — A Succinct Guide by Yash Prakash (Medium)
- [Article] How to Build a Machine Learning App with FastAPI: Dockerize and Deploy the FastAPI Application to Kubernetes by Bravin Wasike (Dev.TO)
- [Article] Building a Machine Learning Model API with Flask: A Step-by-Step Guide by Nilesh Shinde (Medium)
- [Article] Deploying Your Machine Learning Model as a REST API Using Flask by Emmanuel Oludare (Medium)
- [Article] Machine Learning Model Deployment on Heroku Using Flask by Charu Makhijani (Medium)
- [Article] Model Deployment using Flask by Ravindra Sharma (Medium)
- [Article] Deploy a Machine Learning Model using Flask: Step-By-Step by Claudio Sabato (CodeFather.Tech)
- [Article] How to Deploy a Machine Learning Model using Flask? by DataDance.AI Team (DataDance.AI)
- [Article] A Comprehensive Guide on Deploying Machine Learning Models with Flask by MachineLearningModels.Org Team (MachineLearningModels.Org)
- [Article] How to Deploy Machine Learning Models with Flask and Docker by Usama Malik (Medium)
- [Article] Deploying Machine Learning Models with Flask: A Step-by-Step Guide by Sukma Hanifa (Medium)
- [Article] Machine Learning Model Deployment on Heroku Using Flask by Charu Makhijani (Medium)
- [Article] Complete Guide on Model Deployment with Flask and Heroku by Tarek Ghanoum (Medium)
- [Article] Turning Machine Learning Models into APIs in Python by Sayak Paul (DataCamp)
- [Article] Machine Learning, Pipelines, Deployment and MLOps Tutorial by Moez Ali (DataCamp)
- [Video Tutorial] Machine Learning Models Deployment with Flask and Docker by Data Science Dojo (YouTube)
- [Video Tutorial] Deploy Machine Learning Model Flask by Stats Wire (YouTube)
- [Video Tutorial] Deploy Machine Learning Models with Flask | Using Render to host API and Get URL :Step-By-Step Guide by Prachet Shah (YouTube)
- [Video Tutorial] Deploy Machine Learning Model using Flask by Krish Naik (YouTube)
- [Video Tutorial] Deploy Your ML Model Using Flask Framework by MSFTImagine (YouTube)
- [Video Tutorial] Build a Machine Learning App From Scratch with Flask & Docker by Patrick Loeber (YouTube)
- [Video Tutorial] Deploying a Machine Learning Model to a Web with Flask and Python Anywhere by Prof. Phd. Manoel Gadi (YouTube)
- [Video Tutorial] End To End Machine Learning Project With Deployment Using Flask by Data Science Diaries (YouTube)
- [Video Tutorial] Publish ML Model as API or Web with Python Flask by Python ML Daily (YouTube)
- [Video Tutorial] Deploy a Machine Learning Model using Flask API to Heroku by Jackson Yuan (YouTube)
- [Video Tutorial] Deploying Machine Learning Model with FlaskAPI - CI/CD for ML Series by Anthony Soronnadi (YouTube)
- [Video Tutorial] Deploy ML model as Webservice | ML model deployment | Machine Learning | Data Magic by Data Magic (YouTube)
- [Video Tutorial] Deploying Machine Learning Model Using Flask by DataMites (YouTube)
- [Video Tutorial] ML Model Deployment With Flask On Heroku | How To Deploy Machine Learning Model With Flask | Edureka by Edureka (YouTube)
- [Video Tutorial] ML Model Deployment with Flask | Machine Learning & Data Science by Dan Bochman (YouTube)
- [Video Tutorial] How to Deploy ML Solutions with FastAPI, Docker, & AWS by Shaw Talebi (YouTube)
- [Video Tutorial] Deploy ML models with FastAPI, Docker, and Heroku | Tutorial by AssemblyAI (YouTube)
- [Video Tutorial] Machine Learning Model Deployment Using FastAPI by TheOyinbooke (YouTube)
- [Video Tutorial] Creating APIs For Machine Learning Models with FastAPI by NeuralNine (YouTube)
- [Video Tutorial] How To Deploy Machine Learning Models Using FastAPI-Deployment Of ML Models As API’s by Krish Naik (YouTube)
- [Video Tutorial] Machine Learning Model with FastAPI, Streamlit and Docker by CodeTricks (YouTube)
- [Video Tutorial] FastAPI Machine Learning Model Deployment | Python | FastAPI by Stats Wire (YouTube)
- [Video Tutorial] Deploying Machine Learning Models - Full Guide by NeuralNine (YouTube)
- [Video Tutorial] Model Deployment FAST API - Docker | Machine Learning Model Deployment pipeline | FastAPI VS Flask by 360DigiTMG (YouTube)
- [Video Tutorial] Build an AI app with FastAPI and Docker - Coding Tutorial with Tips by Patrick Loeber (YouTube)
- [Video Tutorial] Create a Deep Learning API with Python and FastAPI by DataQuest (YouTube)
- [Video Tutorial] Fast API Machine Learning Web App Tutorial + Deployment on Heroku by Greg Hogg (YouTube)
- [Course] Deeplearning.AI Machine Learning in Production by DeepLearning.AI Team (Coursera)
- [Course] IBM AI Workflow: Enterprise Model Deployment by IBM Team (Coursera)
- [Course] DataCamp Machine Learning Engineer Track by DataCamp Team (DataCamp)
- [Course] DataCamp Designing Machine Learning Workflows in Python by DataCamp Team (DataCamp)
- [Course] DataCamp Building APIs in Python by DataCamp Team (DataCamp)
In [65]:
from IPython.display import display, HTML
display(HTML("<style>.rendered_html { font-size: 15px; font-family: 'Trebuchet MS'; }</style>"))